//  Copyright (c) 2010, Keith Nixon, Sales Engineering, Salesforce.com Inc.
//  All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
//  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
//  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
//  Neither the name of the salesforce.com nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
//  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
//  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
//  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
//  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
//  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
//  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//  *NB - This is NOT a bulkified trigger
//
//  History
//
//  Version  Date            Author          Comments
//  1.0      05-11-2010      Keith Nixon     Initial version
//  1.1      25-11-2010      Mark Sivill     Add logic to create default Account Plan (based on highest end date)
//  1.2      26-11-2010      Mark Sivill     Add workaround logic for Account Plan, only add to record where apply_account_plan__c is true
//                                           no Account Plan no outlet objective created
//

trigger InsertOutletObjectives on Outlet_Definition_Objective__c (before insert) {

    // mark sivill - hardcode account plan to first account created in salesforce (lowest ID value) 
    ID hardcodedAccountPlanID = [SELECT ap.Id FROM Account_Plan__c ap ORDER BY ap.Id DESC LIMIT 1].id;
        
    //1. Using the Outlet (account Id) from the Outlet Definition Objective
    //   record that has just been inserted, we will query for all of the outlets
    //   that are associated with outlet definition.

    Outlet_Definition_Objective__c outletDefObj = Trigger.new.get(0);
    
    Id outletDefId;
    
    if(outletDefObj.Outlet_definition__c != null)
    {
        outletDefId = outletDefObj.Outlet_definition__c;
    }
    else 
    {
        outletDefObj.addError('You must associate an outlet definition');
    }
    
    //2. We query for all of the outlet (account) Ids that 
    //   are associated with the outlet definition. Read 
    //   these outlet (account) Ids into a set.
        
   	Map<Id,Account> outletsMap;
    	
    if(outletDefId != null)
    {
    	
        //instantiate the set of outlet ids if there are 
        //outlet definitions associated with the outlet definition objective.
        outletsMap = new Map<Id,Account>([Select Id, Name, Apply_Account_Plan__c from Account Where Outlet_Definition__c =: outletDefId]);

// System.Debug('**************** InsertOuletObjectives outletsMap after select ' + outletsMap);        									                    
        
        //3. We query for the outlet objective records that are associated with
        //   the objective of the outlet definition objective. We need the 'outlet'
        //   id for each outlet objective and match against the outlet ids returned
        //   above. This ensures that we will not create outlet objectives against
        //   an objective for an outlet that already has the objective. We need to
        //   make sure that there is indeed an outlet definition associated with 
        //   this outlet definition objective record as the relationship between
        //   the two is only LOOKUP. 
        
        if(outletDefObj.Objective__c != null)
        {
            if(!outletsMap.isEmpty())
            {
                for(Outlet_Objectives__c existingOutletObj : [SELECT
                													Id,
                													Account__c,
                													Objective__c
                                                                FROM Outlet_Objectives__c 
                                                                        Where Objective__c =: outletDefObj.Objective__c 
                                                                            AND Account__c IN: outletsMap.keySet()])
                {

// System.Debug('**************** InsertOuletObjectives existingOutletObj ' + existingOutletObj );        									                    

                    if(outletsMap.containsKey(existingOutletObj.Account__c))
                    {   
                        //if we match the existing outlet objective record
                        //against an account, we remove the key from the outletsMap
                        outletsMap.remove(existingOutletObj.Account__c);
                    }
                }
                
                //4. If there any entries left in the outletsMap, then for each one we 
                //   will create an Outlet objective record.
                if(!outletsMap.isEmpty())
                {
                    //5. This list will contain the outlet objectives that we want to insert.
                    //   We populate this whenever we don't find an outlet objective that
                    //   matches an existing outlet that is linked to this outlet definition 
                    //   objective via the outlet definition.
                    List<Outlet_Objectives__c> newOutletObjectives = new List<Outlet_Objectives__c>(); 

// System.Debug('**************** InsertOuletObjectives outletsMap ' + outletsMap); 

					// mark sivill - work out account plan for accounts
					List<Account_Plan__c> accountPlans = [SELECT
																a.Id,
																a.Name,
																a.End_Date__c,
																a.Account__c,
																a.Account__r.Apply_Account_Plan__c
															FROM
																Account_Plan__c a
															WHERE
																a.Account__c IN :outletsMap.keySet()
															ORDER BY
																a.Account__c ASC,
																a.End_Date__c DESC
                										];

// System.Debug('**************** InsertOuletObjectives accountPlans ' + accountPlans); 
													                    
                  	Boolean findAccountPlan = true;
                    for(ID accountId : outletsMap.keySet())
                    {

System.Debug('**************** InsertOuletObjectives looping through accounts with account ' + accountId ); 

                        Outlet_Objectives__c outletObj = new Outlet_Objectives__c();
                        
                        outletObj.Account__c = accountId;
                        outletObj.Objective__c = outletDefObj.Objective__c;

						// mark sivill hardcode Account Plan
						outletObj.Account_Plan__c = hardcodedAccountPlanID;
						 
						//                        
                        // mark sivill change for Account Plan
                        // loop through account plans trying to find match
                        // if no match found raise error
                        //
                   		findAccountPlan = false;
                        for (Account_Plan__c i:accountPlans)
                        {
//                        	if ( (i.Account__c == accountId) && (i.Account__r.Apply_Account_Plan__c == true) )
                        	if (i.Account__c == accountId)
                        	{
                        		outletObj.Account_Plan__c = i.id;
		                   		findAccountPlan = true;
System.Debug('**************** InsertOuletObjectives match for ' + accountID + ' account plan ' + i.name ); 
                        		break;
                        	}
                        }
                        
// System.Debug('**************** InsertOuletObjectives findAccountPlan ' + findAccountPlan ); 
                        if (findAccountPlan == false )
                        {
// System.Debug('**************** InsertOuletObjectives adding error'); 
			                outletDefObj.addError('No Account Plan associated with the Account ' + outletsMap.get(accountId).name + ' record id ' + accountId );            	                        	
                        }
                        else
                        {
// System.Debug('**************** InsertOuletObjectives adding record'); 
	                        newOutletObjectives.add(outletObj);                        	
                        }


                    }   
                    
                    //add our new outlet objectives if 'newOutletObjectives' is not empty;
                    if(!newOutletObjectives.isEmpty())
                    {
                        insert newOutletObjectives;
                    }           
                }                 
            }
            else
            {
                outletDefObj.addError('No outlets associated with the outlet definition objective');
            }
        }   
        else
        {
            outletDefObj.addError('No outlet definition associated with the outlet definition objective');
        }     
    }  
}